package cn.mw.cmdb.virtualization.strategy.handler.sync;

import cn.mw.cmdb.virtualization.dto.VirtualizationStorageDto;
import cn.mw.cmdb.virtualization.param.VirtualizationParam;
import cn.mw.cmdb.virtualization.strategy.handler.SyncEngineDataHandler;
import cn.mw.microMonitorCommon.api.cmdb.VirtualizationDubboService;
import cn.mw.microMonitorCommon.entity.UnitResult;
import cn.mw.microMonitorCommon.entity.cmdb.DataSourceInstanceVo;
import cn.mw.microMonitorCommon.entity.cmdb.DataSourceMappingRuleInfo;
import cn.mw.microMonitorCommon.entity.cmdb.VirtualizationSyncVo;
import cn.mw.microMonitorCommon.entity.common.MwSyncEngineDto;
import cn.mw.microMonitorCommon.enums.EngineTypeEnum;
import cn.mw.microMonitorCommon.enums.SyncEngineTypeEnum;
import cn.mw.microMonitorCommon.enums.VcenterTypeEnum;
import cn.mw.microMonitorCommon.util.RSAUtils;
import cn.mw.microMonitorCommon.util.UnitUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;
import vijava.com.vmware.vim25.mo.*;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.net.URL;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @description vcenter数据处理
 */
@Service
@Slf4j
public class SyncEngineVcenterDataHandler extends SyncEngineDataHandler {
    
    private final String unit = "B";

    @DubboReference(check = false,timeout = 10000000)
    private VirtualizationDubboService virtualizationDubboService;
    
    @Override
    public SyncEngineTypeEnum handlerType() {
        return SyncEngineTypeEnum.VCenter;
    }

    @Override
    public List<VirtualizationStorageDto> getVirtualizationSyncStorageInfo(VirtualizationParam param, MwSyncEngineDto engineDto) {
        String vmType = param.getVmType();
        VcenterTypeEnum vcenterTypeEnum = null;
        if(StringUtils.isNotEmpty(vmType)){
            vcenterTypeEnum = VcenterTypeEnum.getVcenterTypeEnum(vmType);
        }
        List<VirtualizationStorageDto> storageDtos = vCenterConnect(engineDto, vcenterTypeEnum, param.getDataId(),param);
        return storageDtos;
    }

    @Override
    public void syncVirtualizationData(MwSyncEngineDto engineDto, VirtualizationParam param) {
        try {
            VcenterTypeEnum[] vcenterTypeEnums = VcenterTypeEnum.values();
            List<VirtualizationSyncVo> syncVoList = new ArrayList<>();
            //数据组装
            for (VcenterTypeEnum vcenterTypeEnum : vcenterTypeEnums) {
                if(StringUtils.isEmpty(vcenterTypeEnum.getApi())){continue;}
                VirtualizationSyncVo syncVo = new VirtualizationSyncVo();
                syncVo.setEngineId(engineDto.getId());
                syncVo.setEngineDto(engineDto);
                syncVo.setTypeEnum(vcenterTypeEnum);
                syncVoList.add(syncVo);
            }
            log.info("SyncEngineVcenterDataHandler{} syncVirtualizationData() syncVoList()>>>"+syncVoList);
            List<DataSourceInstanceVo> instanceVos = virtualizationDubboService.syncVcenterData(syncVoList);
            handlerInstanceData(instanceVos,param.getEngineId(),param);
        }catch (Throwable e){
            log.error("vcenter数据同步失败",e);
        }
    }

    private List<VirtualizationStorageDto> vCenterConnect(MwSyncEngineDto engineDto,VcenterTypeEnum vcenterTypeEnum,String dataId,VirtualizationParam param){
        List<VirtualizationStorageDto> storageDtos = new ArrayList<>();
        try {
            String vCenterUrl = engineDto.getProtocolType()+"://"+engineDto.getIp()+"/sdk";
            //密码解密
            String password = RSAUtils.decryptData(engineDto.getUserAuth(), RSAUtils.RSA_PRIVATE_KEY);
            ServiceInstance si = new ServiceInstance(new URL(vCenterUrl), engineDto.getAccount(), password, true);
            Folder rootFolder = si.getRootFolder();
            InventoryNavigator inventoryNavigator = new InventoryNavigator(rootFolder);
            List<Datastore> datastoreData = new ArrayList<>();
            if(dataId == null || vcenterTypeEnum == null){
                //查询所有存储
                ManagedEntity[] datacenterEntity  = inventoryNavigator.searchManagedEntities(VcenterTypeEnum.DATACNETER.getType());
                for (ManagedEntity entity : datacenterEntity) {
                    Datastore[] data = getDatastoreData(entity, VcenterTypeEnum.DATACNETER);
                    datastoreData.addAll(Arrays.asList(data));
                }
            }else{
                ManagedEntity entity = inventoryNavigator.searchManagedEntity(vcenterTypeEnum.getType(), param.getInstanceName());
                Datastore[] data = getDatastoreData(entity, vcenterTypeEnum);
                datastoreData.addAll(Arrays.asList(data));
            }
            if(CollectionUtils.isEmpty(datastoreData)){return storageDtos;}
            for (Datastore datastore : datastoreData) {
                VirtualizationStorageDto storageDto = new VirtualizationStorageDto();
                storageDto.setStorageName(datastore.getName());
                if(datastore.getSummary() != null){
                    //总存储
                    long totalStorage = datastore.getSummary().getCapacity();
                    long freeStorage = datastore.getSummary().getFreeSpace();
                    if(totalStorage == 0){continue;}
                    BigDecimal use = new BigDecimal(totalStorage).subtract(new BigDecimal(freeStorage));
                    BigDecimal decimal = use.divide(new BigDecimal(totalStorage),2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                    //单位转换
                    UnitResult totalResult = UnitUtil.getConvertedValue(new BigDecimal(totalStorage), unit);
                    storageDto.setTotalCapacity(totalResult.getValue()+totalResult.getUnits());
                    UnitResult freeResult = UnitUtil.getConvertedValue(new BigDecimal(freeStorage), unit);
                    storageDto.setAvailableCapacity(freeResult.getValue()+freeResult.getUnits());
                    storageDto.setStorageUsageRate(decimal.setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue()+"%");
                    storageDtos.add(storageDto);
                }
            }
        }catch (Throwable e){
            log.error("vCenterConnect error",e);
        }
        return storageDtos;
    }


    private Datastore[] getDatastoreData(ManagedEntity entity,VcenterTypeEnum vcenterTypeEnum) throws RemoteException {
        Datastore[] datastores = null;
        switch (vcenterTypeEnum){
            case DATACNETER:
                Datacenter datacenter = (Datacenter) entity;
                datastores = datacenter.getDatastores();
                break;
            case CLUSTER:
                ClusterComputeResource cluster = (ClusterComputeResource) entity;
                datastores = cluster.getDatastores();
                break;
            case HOSTSYSTEM:
                HostSystem system = (HostSystem) entity;
                datastores = system.getDatastores();
        }
        return datastores;
    }
}
